package org.broncho.ccs;

import static org.broncho.ccs.Task.FLAGE_OP_N;
import static org.broncho.ccs.Task.FLAGE_OP_Y;
import static org.broncho.ccs.Task.MOD_VALUE;

import org.broncho.ccs.base.ComputeTemplate;
import org.broncho.ccs.util.FileUtil;

/**
 * 计算执行流程实现
 * 
 * @author ZhangXiao
 * @time 2013年9月1日
 * 
 * @version 1.0
 * @since 1.5+
 */
public class Compute extends ComputeTemplate {

	/**
	 * @see org.broncho.ccs.Task {@link org.broncho.ccs.Task}
	 */
	private Task task;
	/**
	 * 记录一次计算任务的状态信息
	 */
	private boolean[] status;
	/**
	 * 记录一次计算任务的结果值信息
	 */
	private byte[] operator;
	/**
	 * 任务启动信息
	 */
	private static String START = "Task Start...";
	/**
	 * 任务结束信息
	 */
	private static String END = "Task End...";

	/**
	 * 构造方法
	 * 
	 * @param task
	 *            {@link org.broncho.ccs.Task}
	 */
	public Compute(Task task) {
		this.setTask(task);
	}

	@Override
	public void start() {
		System.out.println(START);
	}

	@Override
	public void init() {
		int edge = this.task.getEdge();
		int number = edge * edge;
		status = new boolean[number];
		operator = new byte[number];
		System.out.println("Init Edge=" + edge + "...");
	}

	@Override
	public void initValue() {
		int edge = this.task.getEdge();
		int number = edge * edge;
		for (int i = 0; i < number; i++) {
			status[i] = false;
			operator[i] = FLAGE_OP_N;
		}
		System.out.println("InitValue status[i], operator[i]...");
	}

	@Override
	public void initStrategy(int sid) {
		this.task.setImage("" + sid);
		int column = 0;
		int temp = sid;
		while (true) {
			if (temp == 0) {
				break;
			}
			byte tag = (byte) (temp % MOD_VALUE);
			if (tag == FLAGE_OP_Y) {
				operator[column] = FLAGE_OP_Y;
			}
			if (tag == FLAGE_OP_N) {
				operator[column] = FLAGE_OP_N;
			}
			temp /= MOD_VALUE;
			column++;
		}
		System.out.println("InitStrategy operator[i] Values...");
	}

	@Override
	public void execute() {
		int edge = this.task.getEdge();
		// 计算时间
		long start = System.currentTimeMillis();
		// 遍历第0行
		for (int column = 0; column < edge; column++) {
			if (this.operator[column] == FLAGE_OP_Y) {
				this.changeStatus(column);
			}
		}
		// 遍历第[1, edge)行
		for (int row = 1; row < edge; row++) {
			for (int column = 0; column < edge; column++) {
				int index = row * edge + column;
				int top = index - edge;
				if (!this.status[top]) {
					this.operator[index] = FLAGE_OP_Y;
					this.changeStatus(index);
				}
			}
		}
		// 计算结束
		long end = System.currentTimeMillis();
		this.task.setWastetime(this.timer(start, end));
		// 设置计算结果
		for (int i = 0, j = this.status.length; i < j; i++) {
			if (!this.status[i]) {
				this.task.setResult(false);
				break;
			} else {
				this.task.setResult(true);
			}
		}
		System.out.println("Execute Current Task...");
	}

	@Override
	public void outputMessage() {
		if (this.task.isResult()) {
			// 执行输出文件操作
			FileUtil.createResultFile(task, this.operator);
			FileUtil.createResultImage(task, this.operator);
		}
		System.out.println("OutputMessage Log And Image...");
	}

	@Override
	public void end() {
		System.out.println(END);
	}

	/**
	 * <strong>运行计算方法</strong>
	 */
	public void runTask() {
		int start = this.task.getStart();
		int end = this.task.getEnd();
		for (int sid = start; sid < end; sid++) {
			System.out.println(">>>Task " + sid);
			this.run(sid);
		}
	}

	/**
	 * 设置当前执行的任务
	 * 
	 * @param task
	 *            {@link org.broncho.ccs.Task}
	 */
	public void setTask(Task task) {
		this.task = task;
	}

	/**
	 * 获取当前任务
	 * 
	 * @return 任务对象
	 */
	public Task getTask() {
		return task;
	}

	/**
	 * 将一个计算的执行时间格式化字符
	 * 
	 * @param start
	 *            开始时间
	 * @param end
	 *            结束时间
	 * @return 时间格式字符串<strong>eg:10h20m33s890ms</strong>
	 */
	private String timer(long start, long end) {
		long ms = end - start;
		String result = "";
		long h = ms / 3600000;
		ms = ms % 36000;
		long m = ms / 60000;
		ms = ms % 60000;
		long s = ms / 1000;
		ms = ms % 1000;
		result = h + "h" + m + "m" + s + "s" + ms + "ms";
		return result;
	}

	/**
	 * 改变状态数组元素的状态
	 * 
	 * @param index
	 *            数组下标
	 */
	private void changeStatus(int index) {
		status[index] = !status[index];
		changeFourSidesStatus(index);
	}

	/**
	 * 改变状态数组的上下左右元素转台
	 * 
	 * @param index
	 *            数组下标
	 */
	private void changeFourSidesStatus(int index) {
		int edge = this.task.getEdge();
		int row = index / edge;
		int column = index % edge;
		int top = row - 1;
		int buttom = row + 1;
		int left = column - 1;
		int right = column + 1;
		if (top >= 0) {
			int rowcolumn = top * edge + column;
			status[rowcolumn] = !status[rowcolumn];
		}
		if (buttom < edge) {
			int rowcolumn = buttom * edge + column;
			status[rowcolumn] = !status[rowcolumn];
		}
		if (left >= 0) {
			int rowcolumn = index - 1;
			status[rowcolumn] = !status[rowcolumn];
		}
		if (right < edge) {
			int rowcolumn = index + 1;
			status[rowcolumn] = !status[rowcolumn];
		}
	}
}
